/*++
 
 Copyright (c) Microsoft Corporation. 

 This source code is subject to terms and conditions of the Microsoft
 Public License. A copy of the license can be found in the License.txt
 file at the root of this distribution. By using this source code in 
 any fashion, you are agreeing to be bound by the terms of the Microsoft
 Public License.

 You must not remove this notice, or any other, from this software.

Module Name:

    SensorDdi.cpp

Abstract:

      This module implements the ISensorDriver interface which is used
      by the Sensor Class Extension.
--*/

#include "internal.h"
#include "SensorDdi.h"
#include "sensorddi.tmh"

#include "WpdObjectProperties.h"

/////////////////////////////////////////////////////////////////////////
//
// CSensorDdi()
//
// Constructor.
//
/////////////////////////////////////////////////////////////////////////
CSensorDdi::CSensorDdi() :
    m_properties(NULL)
{

}

/////////////////////////////////////////////////////////////////////////
//
// ~CSensorDdi()
//
// Destructor
//
/////////////////////////////////////////////////////////////////////////
CSensorDdi::~CSensorDdi()
{

}


/////////////////////////////////////////////////////////////////////////
//
// CSensorDdi::OnGetSupportedSensorObjects
//
// Routine Description:
//
//  This method is called by Sensor Class Extension during the initialize procedure to get 
//  the list of sensor objects and their supported properties.
//  
//  NOTE: This driver supports four sensors: Passive Infrared (PIR), Compass, Ultrasonic distance, and Dual-Axis accelerometer
//
// Arguments:
//
//  ppPortableDeviceValuesCollection - A double IPortableDeviceValuesCollection pointer
//                                     that receives the set of Sensor property values
//
// Return Value:
//
//  Status
// 
//
/////////////////////////////////////////////////////////////////////////
HRESULT CSensorDdi::OnGetSupportedSensorObjects(
        __out IPortableDeviceValuesCollection** ppPortableDeviceValuesCollection
        )
{
    HRESULT hr = S_OK;

    // CoCreate a collection to store the sensor object identifiers.
    hr = CoCreateInstance(CLSID_PortableDeviceValuesCollection,
                              NULL,
                              CLSCTX_INPROC_SERVER,
                              IID_IPortableDeviceValuesCollection,
                              (VOID**) ppPortableDeviceValuesCollection);

	// Temperature sensor
    CComBSTR objectId = SENSOR_TEMPERATURE_ID;
    CComPtr<IPortableDeviceKeyCollection> pKeys;
    CComPtr<IPortableDeviceValues> pValues;

    if (hr == S_OK)
    {
        hr = OnGetSupportedProperties(objectId, &pKeys);
    }

    if (hr == S_OK)
    {
        hr = m_properties->OnGetPropertyValues( objectId, pKeys, &pValues );
    }

    if (hr == S_OK)
    {
        hr = (*ppPortableDeviceValuesCollection)->Add(pValues);
    }

    pKeys.Release();
    pValues.Release();

	// Passive Infrared (PIR) sensor
    objectId = SENSOR_PIR_ID;

    if (hr == S_OK)
    {
        hr = OnGetSupportedProperties(objectId, &pKeys);
    }

    if (hr == S_OK)
    {
        hr = m_properties->OnGetPropertyValues( objectId, pKeys, &pValues );
    }

    if (hr == S_OK)
    {
        hr = (*ppPortableDeviceValuesCollection)->Add(pValues);
    }

    pKeys.Release();
    pValues.Release();

	// Ultrasonic distance sensor
    objectId = SENSOR_PROXIMITY_ID;

    if (hr == S_OK)
    {
        hr = OnGetSupportedProperties(objectId, &pKeys);
    }

    if (hr == S_OK)
    {
        hr = m_properties->OnGetPropertyValues( objectId, pKeys, &pValues );
    }

    if (hr == S_OK)
    {
        hr = (*ppPortableDeviceValuesCollection)->Add(pValues);
    }

    pKeys.Release();
    pValues.Release();

	// Compass 
    objectId = SENSOR_COMPASS_ID;

    if (hr == S_OK)
    {
        hr = OnGetSupportedProperties(objectId, &pKeys);
    }

    if (hr == S_OK)
    {
        hr = m_properties->OnGetPropertyValues( objectId, pKeys, &pValues );
    }

    if (hr == S_OK)
    {
        hr = (*ppPortableDeviceValuesCollection)->Add(pValues);
    }

    pKeys.Release();
    pValues.Release();

	// Dual-Axis accelerometer
    objectId = SENSOR_DUAL_AXIS_ID;
    if (hr == S_OK)
    {
        hr = OnGetSupportedProperties(objectId, &pKeys);
    }

    if (hr == S_OK)
    {
        hr = m_properties->OnGetPropertyValues( objectId, pKeys, &pValues );
    }

    if (hr == S_OK)
    {
        hr = (*ppPortableDeviceValuesCollection)->Add(pValues);
    }

	pKeys.Release();
    pValues.Release();

	// Three-Axis accelerometer
    objectId = SENSOR_THREE_AXIS_ID;
    if (hr == S_OK)
    {
        hr = OnGetSupportedProperties(objectId, &pKeys);
    }

    if (hr == S_OK)
    {
        hr = m_properties->OnGetPropertyValues( objectId, pKeys, &pValues );
    }

    if (hr == S_OK)
    {
        hr = (*ppPortableDeviceValuesCollection)->Add(pValues);
    }

    return hr;
}

/////////////////////////////////////////////////////////////////////////
//
// CSensorDdi::OnGetSupportedProperties
//
// Routine Description:
//
//  This method is called by Sensor Class Extension to get the list of supported properties
//  for a particular Sensor.
//  
// Arguments:
//
//  ObjectID - String that represents the object whose supported property keys are being requested
//  ppKeys - An IPortableDeviceKeyCollection to be populated with supported PROPERTYKEYs
//
// Return Value:
//  Status
// 
//
/////////////////////////////////////////////////////////////////////////
HRESULT CSensorDdi::OnGetSupportedProperties(
        __in  LPWSTR ObjectID,
        __out IPortableDeviceKeyCollection** ppKeys
        )
{
    HRESULT hr = S_OK;

    hr = m_properties->OnGetSupportedProperties( ObjectID, ppKeys );

    return hr;
}

/////////////////////////////////////////////////////////////////////////
//
// CSensorDdi::OnGetSupportedDataFields
//
// Routine Description:
//
//  This method is called by Sensor Class Extension to get the list of supported data fields
//  for a particular Sensor.
//  
// Arguments:
//
//  ObjectID - String that represents the object whose supported property keys are being requested
//  ppKeys - An IPortableDeviceKeyCollection to be populated with supported PROPERTYKEYs
//
// Return Value:
//  Status
// 
//
/////////////////////////////////////////////////////////////////////////
HRESULT CSensorDdi:: OnGetSupportedDataFields(
        __in  LPWSTR ObjectID,
        __out IPortableDeviceKeyCollection** ppKeys
        )
{
    HRESULT hr = S_OK;

    hr = m_properties->OnGetSupportedDataFields( ObjectID, ppKeys );

    return hr;
}

/////////////////////////////////////////////////////////////////////////
//
// CSensorDdi::OnGetSupportedEvents
//
// Routine Description:
//
//  This method is called by Sensor Class Extension to get the list of supported events
//  for a particular Sensor.
//  
// Arguments:
//
// ObjectID - String that represents the object whose supported property keys are being requested
//  ppSupportedEvents - A set of GUIDs that represent the supported events
//  pulEventCount - Count of the number of events supported
//
// Return Value:
//  Status
// 
//
/////////////////////////////////////////////////////////////////////////
HRESULT CSensorDdi::OnGetSupportedEvents(
        __in  LPWSTR ObjectID,
        __out GUID **ppSupportedEvents,
        __out ULONG *pulEventCount
        )
{
    if(NULL == ObjectID ||
       NULL == ppSupportedEvents ||
       NULL == pulEventCount)
    {
        return E_POINTER;
    }

    HRESULT hr = S_OK;

    // Allocate a buffer for one event type GUID.
    // The platform will free this memory.
    GUID* pBuf = (GUID*)CoTaskMemAlloc(sizeof(GUID)*2);

    if(pBuf != NULL)
    {
        pBuf[0] = SENSOR_EVENT_DATA_UPDATED; // data event
        pBuf[1] = SENSOR_EVENT_STATE_CHANGED;

        // Return the pointer to the buffer and the count.
        *ppSupportedEvents = pBuf;
        *pulEventCount = 2;
        }
    else // Failed to allocate the GUID buffer.
    {
        hr = E_OUTOFMEMORY;

        *ppSupportedEvents = NULL;
        *pulEventCount = 0;
    }

    return hr;
}

/////////////////////////////////////////////////////////////////////////
//
// CSensorDdi::OnGetProperties
//
// Routine Description:
//
//  This method is called by Sensor Class Extension to get Sensor property values 
//  for a particular Sensor.
//  
// Arguments:
//
//  ObjectID - String that represents the object whose supported property keys are being requested
// 
//
// Return Value:
//  Status
// 
//
/////////////////////////////////////////////////////////////////////////
HRESULT CSensorDdi:: OnGetProperties(
        __in  IWDFFile* appId,
        __in  LPWSTR ObjectID,
        __in  IPortableDeviceKeyCollection* pKeys,
        __out IPortableDeviceValues** ppValues
        )
{
   
    UNREFERENCED_PARAMETER(appId);

    HRESULT hr = S_OK;

    if ((ObjectID == NULL) ||
        (pKeys       == NULL) ||
        (ppValues     == NULL))
    {
        hr = E_INVALIDARG;
        return hr;
    }

    hr = m_properties->OnGetPropertyValues( ObjectID, pKeys, ppValues );

    return hr;
}

HRESULT CSensorDdi:: OnGetDataFields(
        __in  IWDFFile* appId,
        __in  LPWSTR ObjectID,
        __in  IPortableDeviceKeyCollection* pKeys,
        __out IPortableDeviceValues** ppValues
        )
{
    UNREFERENCED_PARAMETER(appId);

    HRESULT hr = S_OK;

    if ((ObjectID == NULL) ||
        (pKeys       == NULL) ||
        (ppValues     == NULL))
    {
        hr = E_INVALIDARG;
        return hr;
    }

    hr = m_properties->OnGetDataFields( ObjectID, pKeys, ppValues );

    return hr;
}

HRESULT CSensorDdi:: OnSetProperties(
        __in IWDFFile* appId,
        __in LPWSTR ObjectID,
        __in IPortableDeviceValues* pValues,
        __out IPortableDeviceValues** ppResults
        )
{
    UNREFERENCED_PARAMETER(appId);

    HRESULT hr = S_OK;

    if ((ObjectID == NULL) ||
        (pValues       == NULL) ||
        (ppResults     == NULL))
    {
        hr = E_INVALIDARG;
        return hr;
    }

    hr = m_properties->OnSetPropertyValues( ObjectID, pValues, ppResults );

    return hr;
}

HRESULT CSensorDdi:: OnClientConnect(
        __in IWDFFile* pClientFile,
        __in LPWSTR pwszObjectID
        )
{
    UNREFERENCED_PARAMETER(pClientFile);
    UNREFERENCED_PARAMETER(pwszObjectID);

    HRESULT hr = S_OK;

    return hr;
}

HRESULT CSensorDdi:: OnClientDisconnect(
        __in IWDFFile* pClientFile,
        __in LPWSTR pwszObjectID
        )
{
    UNREFERENCED_PARAMETER(pClientFile);
    UNREFERENCED_PARAMETER(pwszObjectID);

    HRESULT hr = S_OK;

    return hr;
}

HRESULT CSensorDdi:: OnClientSubscribeToEvents(
        __in IWDFFile* pClientFile,
        __in LPWSTR pwszObjectID
        )
{
    UNREFERENCED_PARAMETER(pClientFile);
    UNREFERENCED_PARAMETER(pwszObjectID);

    HRESULT hr = S_OK;

    return hr;
}

HRESULT CSensorDdi:: OnClientUnsubscribeFromEvents(
        __in IWDFFile* pClientFile,
        __in LPWSTR pwszObjectID
        )
{
    UNREFERENCED_PARAMETER(pClientFile);
    UNREFERENCED_PARAMETER(pwszObjectID);

    HRESULT hr = S_OK;

    return hr;
}

HRESULT CSensorDdi:: OnProcessWpdMessage(
        __in IUnknown* pPortableDeviceValuesParamsUnknown,
        __in IUnknown* pPortableDeviceValuesResultsUnknown
        )
{
    UNREFERENCED_PARAMETER(pPortableDeviceValuesParamsUnknown);
    UNREFERENCED_PARAMETER(pPortableDeviceValuesResultsUnknown);

    HRESULT hr = S_OK;

    return hr;
}
